# -*- coding:utf-8 -*-
"""
@Author  :   g1879
@Contact :   g1879@qq.com
"""
from pathlib import Path
from queue import Queue
from threading import Lock
from typing import Union, Tuple, Any, Literal, Optional

from DataRecorder import Recorder
from DrissionPage import SessionOptions
from DrissionPage.base import BasePage
from requests import Session, Response

from ._funcs import FileExistsSetter, PathSetter, BlockSizeSetter
from .mission import Task, Mission, BaseTask

FILE_EXISTS = Literal['add', 'skip', 'rename', 'overwrite']


class DownloadKit(object):
    file_exists: FileExistsSetter = ...
    goal_path: PathSetter = ...
    block_size: BlockSizeSetter = ...

    def __init__(self,
                 goal_path: Union[str, Path] = None,
                 roads: int = 10,
                 session: Union[Session, BasePage] = None,
                 file_exists: FILE_EXISTS = 'rename'):
        self._roads: int = ...
        self._setter: Setter = ...
        self._print_mode: str = ...
        self._log_mode: str = ...
        self._logger: Recorder = ...
        self._retry: int = ...
        self._interval: float = ...
        self.page: Optional[BasePage] = ...
        self._waiting_list: Queue = ...
        self._session: Session = ...
        self._running_count: int = ...
        self._missions_num: int = ...
        self._missions: dict = ...
        self._threads: dict = ...
        self._timeout: Union[int, float] = ...
        self._stop_printing: bool = ...
        self._lock: Lock = ...
        self._copy_cookies: bool = ...

        self.goal_path: str = ...
        self.file_exists: FILE_EXISTS = ...
        self.split: bool = ...
        self.block_size: Union[str, int] = ...

    def __call__(self,
                 file_url: str,
                 goal_path: Optional[str, Path] = None,
                 rename: str = None,
                 file_exists: FILE_EXISTS = None,
                 show_msg: bool = True,
                 timeout: Optional[float] = None,
                 params: Optional[dict] = ...,
                 data: Any = ...,
                 json: Any = ...,
                 headers: Optional[dict] = ...,
                 cookies: Any = ...,
                 files: Any = ...,
                 auth: Any = ...,
                 allow_redirects: bool = ...,
                 proxies: Optional[dict] = ...,
                 hooks: Any = ...,
                 stream: Any = ...,
                 verify: Any = ...,
                 cert: Any = ...) -> tuple: ...

    @property
    def set(self) -> Setter: ...

    @property
    def roads(self) -> int: ...

    @property
    def retry(self) -> int: ...

    @property
    def interval(self) -> float: ...

    @property
    def timeout(self) -> float: ...

    @property
    def waiting_list(self) -> Queue: ...

    @property
    def session(self) -> Session: ...

    @property
    def is_running(self) -> bool: ...

    @property
    def missions(self) -> dict: ...

    def add(self,
            file_url: str,
            goal_path: Optional[str, Path] = None,
            rename: str = None,
            file_exists: FILE_EXISTS = None,
            split: bool = None,
            timeout: Optional[float] = None,
            params: Optional[dict] = ...,
            data: Any = None,
            json: Optional[dict, str] = ...,
            headers: Optional[dict] = ...,
            cookies: Any = ...,
            files: Any = ...,
            auth: Any = ...,
            allow_redirects: bool = ...,
            proxies: Optional[dict] = ...,
            hooks: Any = ...,
            stream: Any = ...,
            verify: Any = ...,
            cert: Any = ...) -> Mission: ...

    def download(self,
                 file_url: str,
                 goal_path: Optional[str, Path] = None,
                 rename: str = None,
                 file_exists: FILE_EXISTS = None,
                 show_msg: bool = True,
                 timeout: Optional[float] = None,
                 params: Optional[dict] = ...,
                 data: Any = ...,
                 json: Any = ...,
                 headers: Optional[dict] = ...,
                 cookies: Any = ...,
                 files: Any = ...,
                 auth: Any = ...,
                 allow_redirects: bool = ...,
                 proxies: Optional[dict] = ...,
                 hooks: Any = ...,
                 stream: Any = ...,
                 verify: Any = ...,
                 cert: Any = ...) -> tuple: ...

    def _run_or_wait(self, mission: BaseTask) -> None: ...

    def _run(self, ID: int, mission: BaseTask) -> None: ...

    def get_mission(self, mission_or_id: Union[int, Mission]) -> Mission: ...

    def get_failed_missions(self) -> list: ...

    def wait(self,
             mission: Union[int, Mission] = None,
             show: bool = False,
             timeout: float = None) -> Optional[tuple]: ...

    def cancel(self) -> None: ...

    def show(self, asyn: bool = True, keep: bool = False) -> None: ...

    def _show(self, wait: float, keep: bool = False) -> None: ...

    def _connect(self, url: str, session: Session, method: str, **kwargs) -> Tuple[Union[Response, None], str]: ...

    def _get_usable_thread(self) -> Optional[int]: ...

    def _stop_show(self) -> None: ...

    def _when_mission_done(self, mission: Mission) -> None: ...

    def _download(self,
                  mission_or_task: Union[Mission, Task],
                  thread_id: int) -> None: ...


class Setter(object):
    def __init__(self, downloadKit: DownloadKit):
        self._downloadKit: DownloadKit = ...

    @property
    def DownloadKit(self) -> DownloadKit: ...

    @property
    def if_file_exists(self) -> FileExists: ...

    @property
    def log_mode(self) -> LogSet: ...

    def driver(self, driver: Union[Session, BasePage, SessionOptions]) -> None: ...

    def roads(self, num: int) -> None: ...

    def retry(self, times: int) -> None: ...

    def interval(self, seconds: float) -> None: ...

    def timeout(self, seconds: float) -> None: ...

    def goal_path(self, path: Union[str, Path]) -> None: ...

    def split(self, on_off: bool) -> None: ...

    def block_size(self, size: Union[str, int]) -> None: ...

    def proxies(self, http: str = None, https: str = None) -> None: ...


class LogSet(object):
    def __init__(self, setter: Setter):
        self._setter: Setter = ...

    def log_path(self, log_path: Union[str, Path]) -> None: ...

    def print_all(self) -> None: ...

    def print_failed(self) -> None: ...

    def print_nothing(self) -> None: ...

    def log_all(self) -> None: ...

    def log_failed(self) -> None: ...

    def log_nothing(self) -> None: ...


class FileExists(object):
    def __init__(self, setter: Setter):
        self._setter: Setter = ...

    def __call__(self, mode: FILE_EXISTS): ...

    def skip(self) -> None: ...

    def rename(self) -> None: ...

    def overwrite(self) -> None: ...
